package util;

import java.util.List;

import org.apache.commons.collections15.Transformer;

import spatialindex.Circle;

import edu.uci.ics.jung.algorithms.shortestpath.DijkstraShortestPath;
import edu.uci.ics.jung.graph.Graph;
import graph.GraphEdge;
import graph.GraphNode;

public class MathUtil {
	/**
	 * Computes the Euclidean Distance between two points.
	 * 
	 * @return distance
	 * @param x1
	 *            x-coordinate of the 1st point
	 * @param y1
	 *            y-coordinate of the 1st point
	 * @param x2
	 *            x-coordinate of the 2nd point
	 * @param y2
	 *            y-coordinate of the 2nd point
	 */
	public static double computeEuclideanDistance(double x1, double y1,
			double x2, double y2) {
		double xDist = Math.abs(x1 - x2);
		double yDist = Math.abs(y1 - y2);
		return Math.sqrt(xDist * xDist + yDist * yDist);
	}

	/**
	 * Compute Euclidean distance for multi-dimensional points
	 * 
	 * @param point1
	 * @param point2
	 * @return Euclidean distance between point1 and point2
	 */
	public static double computeEuclideanDistance(double[] point1,
			double[] point2) {
		if (point1.length != point2.length)
			throw new IllegalArgumentException(
					"MathUtil.computeEuclideanDistance has the unmatched number of dimensions.");
		double sumSquare = 0;
		for (int cIndex = 0; cIndex < point1.length; cIndex++) {
			double d = point1[cIndex] - point2[cIndex];
			sumSquare += d * d;

		}
		return Math.sqrt(sumSquare);
	}

	private static Transformer<GraphEdge, Double> wtTransformer = new Transformer<GraphEdge, Double>() {
		public Double transform(GraphEdge edge) {
			return edge.getWeight();
		}
	};

	/**
	 * Compute the network distance between two nodes
	 * 
	 * @param g
	 * @param gns
	 * @param gne
	 * @return the shortest path distance between gns and gne
	 */
	public static double computeNetworkDistance(Graph<GraphNode, GraphEdge> g,
			GraphNode gns, GraphNode gne) {

		DijkstraShortestPath<GraphNode, GraphEdge> alg = new DijkstraShortestPath<GraphNode, GraphEdge>(
				g, wtTransformer);

		Number dist = alg.getDistance(gns, gne);
		return (Double) dist;
	}

	/**
	 * Compute the shortest network distance between a node and an edge
	 * 
	 * @param graph
	 * @param node
	 * @param edge
	 * @return
	 */
	public static double computeNodeToEdgeNetworkDistance(
			Graph<GraphNode, GraphEdge> graph, GraphNode node, GraphEdge edge) {

		DijkstraShortestPath<GraphNode, GraphEdge> alg = new DijkstraShortestPath<GraphNode, GraphEdge>(
				graph, wtTransformer);

		GraphNode src = edge.getSrcNode();
		GraphNode dest = edge.getDestNode();

		double dist_src = alg.getDistance(node, src).doubleValue();
		double dist_dest = alg.getDistance(node, dest).doubleValue();

		return Math.min(dist_src, dist_dest);
	}

	/**
	 * 
	 * @param v1
	 * @param v2
	 * @param v3
	 * @param v4
	 * @return the smallest value among the four
	 */
	public static double min(double v1, double v2, double v3, double v4) {
		double tempv = Math.min(v1, v2);
		if (tempv > v3) {
			tempv = v3;
		}
		if (tempv > v4) {
			tempv = v4;
		}
		return tempv;
	}

}
